#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include <sys/wait.h>
#include <readline/readline.h>
#include <readline/history.h> //gcc main.c -lreadline

#define CLOSE "\001\033[0m\002"                 // 关闭所有属性
#define BLOD  "\001\033[1m\002"                 // 强调、加粗、高亮
#define BEGIN(x,y) "\001\033["#x";"#y"m\002"    // x: 背景，y: 前景


char *cmder[] = {
    "cd",
    "pwd",
    "help",
    "exit",
    "echo"
};

int long_cmd(){
    return sizeof(cmder)/sizeof(char*);
}

int fun_cd(char** char_list){
    if(char_list[1] == NULL){
        printf("Please enter the correct directory\n");
    }else{
        if(chdir(char_list[1]) != 0){
            perror("myshell");
        }
    }
    return 1;
}

int fun_pwd(char** char_list){
    int bufsize = 1024;
    char *buffer = malloc(sizeof(char)*bufsize);
    if (!buffer){
        printf("allocation error\n");
        exit(1);
    }
    while (1){
        if(getcwd(buffer, bufsize) == NULL){
            bufsize += bufsize;
            buffer = realloc(buffer, sizeof(char)*bufsize);
            if (!buffer){
                printf("allocation error\n");
                exit(1);
                }
        }else{
            printf("current working directory : %s\n", buffer);
            free(buffer);
            return 1;
        }
    }
}

int fun_help(char** char_list){
    int i;
    printf("---------------------myshell---------------------\n");
    printf("Type program names and arguments, and hit enter.\n");
    printf("-----------The following are built in:-----------\n");
    for ( i = 0; i < long_cmd(); i++){
        printf("%s\n", cmder[i]);
    }
    printf("Use the man command for information on other programs.\n");
    printf("------------------------------------------------------\n");
    return 1;  
}

int fun_exit(char** char_list){
    printf("-----------------------goodbye-----------------------\n");
    return 0;
}

int fun_echo(char** char_list){
    int i;
    if (char_list[1] == NULL){
        printf("Enter correct output.\n");
    }else{
        for ( i = 1; char_list[i] != NULL; i++)
        {
            printf("%s ", char_list[i] );
        }
        printf("\n");
    }
    return 1;
}

int (*funcs[])(char**) = {
    &fun_cd,
    &fun_pwd,
    &fun_help,
    &fun_exit,
    &fun_echo
};

int process(char** char_list){
    pid_t pid = fork(),wpid;
    int status;
    if (pid == 0){
        if (execvp(char_list[0], char_list) == -1){
            perror("myshell ");
            exit(1);//子进程报错后销毁，返回父进程
        }
    }else if (pid < 0){
        perror("myshell ");
        exit(1);
    }else{
        do{
            wpid = waitpid(pid, &status, WUNTRACED);
        }while (!WIFEXITED(status) && !WIFSIGNALED(status));
    }
    return 1;
}


char *shell_readline() {
    int bufsize = 1024;
    int i = 0;
    char *buffer = malloc(sizeof(char)*bufsize);
    int c;

    if(!buffer){
        printf("allocation error\n");
        exit(1);
    }
    while (1)
    {
        c = getchar();
        if(c == EOF || c == '\n'){
            buffer[i] = '\0';
            return buffer;
        }else{
            buffer[i] = c;
            i++;
        }
        if(i >= bufsize){
            bufsize += bufsize;
            buffer = realloc(buffer, sizeof(char)*bufsize);
            if(!buffer){
                printf("allocation error\n");
                exit(1);
            }
        }
    }
}

char **cut_line(char *line){
    int bufsize = 64, i = 0;
    char **tokens = malloc(bufsize*sizeof(char*));
    char *token;

    if(!tokens){
        printf("allocation error\n");
        exit(1);
    } 
    token = strtok(line, " ");
    while (token != NULL)
    {
        tokens[i] = token;
        i++;
        if(i >= bufsize){
            bufsize += bufsize;
            tokens = realloc(tokens, bufsize*sizeof(char*));
            if(!tokens){
                printf("allocation error\n");
                exit(1);
            }
        }
        token = strtok(NULL, " ");
    }
    tokens[i] = NULL;
    return tokens;
}

int execute(char **char_list){
    int i;
    if(char_list[0] == NULL){
        return 1;
    }
    for ( i = 0; i < long_cmd(); i++){
        if (strcmp(char_list[0], cmder[i]) == 0){
            return (*funcs[i])(char_list); 
        }
    }
    return process(char_list);//调用进程
}

int loop() {
    char *line;
    char **char_list;
    int state = 1;

    do{
        //printf("myshell-> ");
        //line = shell_readline();
        line = readline(BEGIN(49, 34)"Myshell->  "CLOSE);
        if (!line){
            printf("allocation error\n");
            exit(1);
        }
        add_history(line);

          
        char_list = cut_line(line);
        state = execute(char_list);
        
        free(line);
        free(char_list);
    }while(state);
    return 1;
}

int main() {
    //预留配置文件位置
    loop();
    exit(0);
}